package pa165.dominating.species.entities;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.*;
import pa165.dominating.species.dao.PersistObject;
import pa165.dominating.species.exceptions.EntityException;

/**
 * Entity represents simple Environment with some set of Environment Elements.
 *
 * @author Stanislau Dubrouski
 */
@NamedQueries({
    @NamedQuery(name = "getAllEnvironments", query = "SELECT e FROM Environment e")})
@Entity
public class Environment implements Serializable, PersistObject {

    private static final long serialVersionUID = 892364162348274L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Column(nullable = false)
    private String name;
    @Column(nullable = false)
    private String description;
    @ManyToMany(fetch = FetchType.EAGER) //fetch for tests to pass
    @JoinTable(
            name = "ENVIRONMENT_ELEMENT",
            joinColumns = {
        @JoinColumn(name = "ENVIRONMENT_ID", referencedColumnName = "ID")},
            inverseJoinColumns = {
        @JoinColumn(name = "ELEMENT_ID", referencedColumnName = "ID")})
    private List<Element> elements;

    public Environment() {
    }

    public Environment(String name, String description) {
        this.name = name;
        this.description = description;
        this.elements = new ArrayList<>();
    }

    @Override
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public List<Element> getElements() {
        return elements;
    }

    public void setElements(List<Element> elements) {
        this.elements = elements;
    }

    public void addElement(Element el) {
        if (this.elements == null) {
            elements = new ArrayList<>();
        }
        if (el == null) {
            throw new IllegalArgumentException("Element el cannot be null.");
        }
        if (el.getId() == null) {
            throw new IllegalArgumentException("Element " + el + " is not in DB - id is null.");
        }

        if (this.elements.contains(el)) {
            //TODO: Do nothing - element already added
            return;
        }
        elements.add(el);
    }

    public void removeElement(Element el) {
        if (el == null) {
            throw new IllegalArgumentException("Element el cannot be null.");
        }
        if (el.getId() == null) {
            throw new IllegalArgumentException("Element " + el + " is not in DB - id is null.");
        }

        if (this.elements.contains(el)) {
            elements.remove(el);
        } else {
            throw new IllegalArgumentException("Given element " + el + " not found in environment's elems list.");
        }
    }

    public void addMultipleElements(List<Element> elems) {
        if (elems == null) {
            throw new IllegalArgumentException("elems is null");
        }
        for (Element el : elems) {
            this.addElement(el);
        }
    }

    public void removeMultipleElements(List<Element> elems) {
        if (elems == null) {
            throw new IllegalArgumentException("elems is null");
        }
        for (Element el : elems) {
            this.removeElement(el);
        }
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        if (!(object instanceof Environment)) {
            return false;
        }
        Environment other = (Environment) object;
        if (other.getId() == null) {
            throw new EntityException("Environment " + other + " not managed - no id assigned");
        }
        if (this.getId() == null) {
            throw new EntityException("Environment " + this + " not managed - no id assigned");
        }

        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "Environment " + this.getName() + ", id: " + this.getId() + ". " + this.getDescription() + ". Elements follow: " + this.getElements();
    }
}
